﻿using System;
using System.Collections.Generic;
using System.IO;

namespace DotNetNukeMVPWizard.ProjectConfiguration
{
    class MvpMultiProjectConfiguration : IMvpMultiProjectConfiguration
    {
        #region Methods
        public void FillDictionary(Dictionary<string, string> replacementDictionary)
        {
            foreach (IConfigurable item in Placeholders.Values)
            {
                UpdateDictionary(replacementDictionary, item.Key, item.Value);
            };
        }

        /// <summary>
        /// UpdateDictionary performs a "safe" update of a key/value pair. If the key exists, its value is updated; if the key does not exist, the key/value is added as a new entry in the dictionary.
        /// </summary>
        /// <param name="replacementDictionary">An existing Dictionary (by reference)</param>
        /// <param name="key">A string as the key to an entry in the dictionary</param>
        /// <param name="value">A string as the value to store in the dictionary</param>
        private static void UpdateDictionary(Dictionary<string, string> replacementDictionary, string key, string value)
        {
            if (replacementDictionary.ContainsKey(key))
                replacementDictionary[key] = value;
            else
                replacementDictionary.Add(key, value);
        }
        #endregion

        #region Setter Methods
        public void SetIisAppRootUrl(string value)
        {
            Placeholders[Keys.IisAppRootUrl].Value = value;
            Placeholders[Keys.IisUrl].Value = Placeholders[Keys.IisAppRootUrl].Value + "DesktopModules/";
        }
        public void SetPathIisAppRootUrl(string value)
        {
            Placeholders[Keys.PathIisAppRootUrl].Value = value;
            Placeholders[Keys.Dependencies].Value = Placeholders[Keys.PathIisAppRootUrl].Value + "bin";
        }
        public void SetProjectNamespaceName(string value)
        {
            Placeholders[Keys.ProjectNamespaceName].Value = value;
        }
        public void SetParentProjectName(string value)
        {
            Placeholders[Keys.ParentProjectName].Value = value;
            Placeholders[Keys.SafeParentProjectName].Value = Placeholders[Keys.ParentProjectName].Value;
        }
        public void SetYourCompany(string value)
        {
            Placeholders[Keys.YourCompany].Value = value;
            Placeholders[Keys.SafeYourCompany].Value = Placeholders[Keys.YourCompany].Value;
        }
        #endregion

        #region Properties
        private Dictionary<string, IConfigurable> Placeholders { get; set; }

        public string IisUrl { get { return Placeholders[Keys.IisUrl].Value; } }
        public string IisAppRootUrl { get { return Placeholders[Keys.IisAppRootUrl].Value; } }
        public string PathIisAppRootUrl { get { return Placeholders[Keys.PathIisAppRootUrl].Value; } }
        public string Dependencies { get { return Placeholders[Keys.Dependencies].Value; } }
        public string DependenciesGallio { get { return Placeholders[Keys.DependenciesGallio].Value; } }
        public string DependenciesMoq { get { return Placeholders[Keys.DependenciesMoq].Value; } }
        public string DependenciesWatiN { get { return Placeholders[Keys.DependenciesWatiN].Value; } }
        public string ProjectNamespaceName { get { return Placeholders[Keys.ProjectNamespaceName].Value; } }
        public string ParentProjectName { get { return Placeholders[Keys.ParentProjectName].Value; } }
        public string SafeParentProjectName { get { return Placeholders[Keys.SafeParentProjectName].Value; } }
        public string YourCompany { get { return Placeholders[Keys.YourCompany].Value; } }
        public string SafeYourCompany { get { return Placeholders[Keys.SafeYourCompany].Value; } }

        public bool IsValid
        {
            get
            {
                bool isValid = true;
                _ErrorMessages = string.Empty; // HACK: tight dependency between IsValid and ErrorMessages - uses field because a set on the property would cause a circular access & an infinite loop
                foreach (IConfigurable item in Placeholders.Values)
                {
                    if (!item.IsValid)
                    {
                        isValid = false;
                        _ErrorMessages += "\n" + item.ErrorMessage; // HACK: tight dependency between IsValid and ErrorMessages - uses field because a set on the property would cause a circular access & an infinite loop
                    }
                }
                return isValid;
            }
        }


        private string _ErrorMessages;
        public string ErrorMessages
        {
            get
            {
                bool force = IsValid; // HACK: used to force the re-creation of error messages, if any
                return _ErrorMessages;
            }
        }

        public bool IsValidIisAppRootUrl { get { return Placeholders[Keys.IisAppRootUrl].IsValid; } }
        public bool IsValidPathIisAppRootUrl { get { return Placeholders[Keys.PathIisAppRootUrl].IsValid; } }
        public bool IsValidProjectNamespaceName { get { return Placeholders[Keys.ProjectNamespaceName].IsValid; } }
        public bool IsValidParentProjectName { get { return Placeholders[Keys.ParentProjectName].IsValid; } }
        public bool IsValidYourCompany { get { return Placeholders[Keys.YourCompany].IsValid; } }
        #endregion

        #region Constructors
        public MvpMultiProjectConfiguration()
        {
            InitConfigurationItems();
            HuntFor3rdPartyDependencies();
        }

        #region Private Construction Helpers
        private void InitConfigurationItems()
        {
            Placeholders = new Dictionary<string, IConfigurable>();
            Placeholders.Add(Keys.IisUrl, new TextConfiguration(Keys.IisUrl));
            Placeholders.Add(Keys.IisAppRootUrl, new UrlAddressConfiguration(Keys.IisAppRootUrl));
            Placeholders.Add(Keys.PathIisAppRootUrl, new FolderPathConfiguration(Keys.PathIisAppRootUrl));
            Placeholders.Add(Keys.Dependencies, new FolderPathConfiguration(Keys.Dependencies, "The folder path must point to a valid bin folder; this placeholder is tied to the " + Keys.PathIisAppRootUrl + " placeholder."));
            Placeholders.Add(Keys.DependenciesGallio, new FolderPathConfiguration(Keys.DependenciesGallio, string.Empty, true));
            Placeholders.Add(Keys.DependenciesMoq, new FolderPathConfiguration(Keys.DependenciesMoq, string.Empty, true));
            Placeholders.Add(Keys.DependenciesWatiN, new FolderPathConfiguration(Keys.DependenciesWatiN, string.Empty, true));
            Placeholders.Add(Keys.ProjectNamespaceName, new SafeIdentifierConfiguration(Keys.ProjectNamespaceName));
            Placeholders.Add(Keys.ParentProjectName, new TextConfiguration(Keys.ParentProjectName));
            Placeholders.Add(Keys.SafeParentProjectName, new SafeIdentifierConfiguration(Keys.SafeParentProjectName));
            Placeholders.Add(Keys.YourCompany, new TextConfiguration(Keys.YourCompany));
            Placeholders.Add(Keys.SafeYourCompany, new SafeIdentifierConfiguration(Keys.SafeYourCompany));
        }

        private void HuntFor3rdPartyDependencies()
        {
            /*
             * C:\Program Files\Gallio\bin
             *      CreateHintPathFor_Gallio - $dependenciesgallio$      - @"C:\Program Files\Gallio\"
             * 
             * C:\Program Files\Moq.4.0.10827\NET35
             *      CreateHintPathFor_Moq    - $dependenciesmoq$         - @"C:\Program Files\Moq"
             *                                                           - @"C:\Program Files (x86)\Moq"
             *                                                      
             * C:\Program Files (x86)\WatiN-2.0.20.1089-net-2.0\Bin
             *      CreateHintPathFor_WatiN  - $dependencieswatin$       - @"C:\Program Files (x86)\WatiN"
             *                                                           - @"C:\Program Files\WatiN"
             */
            if (Directory.Exists(@"C:\Program Files\Gallio\bin"))
                Placeholders[Keys.DependenciesGallio].Value = @"C:\Program Files\Gallio\bin";

            string[] possiblePaths;

            possiblePaths = Directory.GetDirectories(@"C:\Program Files\", "Moq*");
            if (possiblePaths.Length > 0)
                Placeholders[Keys.DependenciesMoq].Value = possiblePaths[0] + @"\NET35";
            else
            {
                possiblePaths = Directory.GetDirectories(@"C:\", @"Program Files (x86)\Moq*");
                if (possiblePaths.Length > 0)
                    Placeholders[Keys.DependenciesMoq].Value = possiblePaths[0] + @"\NET35";
            }

            possiblePaths = Directory.GetDirectories(@"C:\Program Files\", "WatiN-*");
            if (possiblePaths.Length > 0)
                Placeholders[Keys.DependenciesWatiN].Value = possiblePaths[0] + @"\bin";
            else
            {
                possiblePaths = Directory.GetDirectories(@"C:\", @"Program Files (x86)\WatiN-*");
                if (possiblePaths.Length > 0)
                    Placeholders[Keys.DependenciesWatiN].Value = possiblePaths[0] + @"\bin";
            }

        }
        #endregion
        #endregion

        #region Subclass of Constants
        public class Keys
        {
            public const string IisUrl = "$iisurl$";
            public const string IisAppRootUrl = "$iisapprooturl$";
            public const string PathIisAppRootUrl = "$pathiisapprooturl$";
            public const string Dependencies = "$dependencies$";
            public const string DependenciesGallio = "$dependenciesgallio$";
            public const string DependenciesMoq = "$dependenciesmoq$";
            public const string DependenciesWatiN = "$dependencieswatin$";
            public const string ProjectNamespaceName = "$projectnamespacename$";
            public const string ParentProjectName = "$parentprojectname$";
            public const string SafeParentProjectName = "$safeparentprojectname$";
            public const string YourCompany = "$yourcompany$";
            public const string SafeYourCompany = "$safeyourcompany$";
        }
        #endregion
    }
}
